#include <sea_common>
#include "test_object.h"

// -------------------------------------------------------------------------------------------------

using namespace sea;

class thread : public OsThread
{
private: 
    sea::ref< List > m_list;
    int m_index;
public:
    thread( List* aList, int aIndex ) : m_list( aList ), m_index( aIndex ) { }
    void exec( )
    {
        for( int i = 0; i < 1000; i++ )
        {
            if ( m_index & 0x01 )
            {
                sea::aref obj;
                {
                    OsMutex::Scoped safe( m_list->lock( ) );
                    obj = m_list->get_last( );
                }
                m_list->detach( obj );
            }
            else
            {
                aref a; 
                a << NEW Object;
                m_list->attach_last( a );
            }
        }
    }
};

// -------------------------------------------------------------------------------------------------

class thread1 : public OsThread
{
private: 
    sea::aref m_obj;
public:
    thread1( sea::aref aObj ) : m_obj( aObj ) { }
    void exec( )
    {
        m_obj->detach( 1 );
    }
};

// -------------------------------------------------------------------------------------------------

sea::aref get_x( )
{
    sea::aref a; a << NEW Object;
    return a;
}

// -------------------------------------------------------------------------------------------------


void test_object( )
{
    #define LOCAL_OBJECT( x ) aref x( #x )
    #define LOCAL_LIST( x ) aref x; x << NEW List( #x )
    #define ADD_TO( list, obj ) list.as< sea::List >( )->attach_last( obj )

    #define SHOW_LIST_NAME( x ) SEA_TRACE( "\n\t\t\t*** List of: %s", ( x ).as< sea::List >( )->id( ).get_object( ) ? \
        ( x ).as< sea::List >( )->id( ).get_object( )->as< char >( ) : ( x ).as< sea::List >( )->id( ).get_string( ) )
    
    #define SHOW_LIST( of, x ) SHOW_LIST_NAME( x ); \
        for( HIterator< of > __it( ( x ).as< sea::List >( ) ); *__it; __it.advance( ) )SEA_TRACE( "\t%s", __it->as< char >( ) )

    #define MAKE_LIST( of, x, o1, o2, o3, o4, o5 ) LOCAL_LIST( x ); ADD_TO( x, o1 ); ADD_TO( x, o2 ); ADD_TO( x, o3 ); ADD_TO( x, o4 ); ADD_TO( x, o5 ); SHOW_LIST( of, x )
    #define MAKE_LIST2( of, x, o1, o2 ) LOCAL_LIST( x ); ADD_TO( x, o1 ); ADD_TO( x, o2 ); SHOW_LIST( of, x )
    #define MAKE_LIST_BY( of, x, by, o1, o2, o3, o4, o5 ) aref x; x << NEW List( by ); ADD_TO( x, o1 ); ADD_TO( x, o2 ); ADD_TO( x, o3 ); ADD_TO( x, o4 ); ADD_TO( x, o5 ); SHOW_LIST( of, x )

#if 1
    {
        // Men. Use aggregared object - man-nationality
        LOCAL_OBJECT( norw );
        LOCAL_OBJECT( brit );
        LOCAL_OBJECT( germ );
        LOCAL_OBJECT( swe );
        LOCAL_OBJECT( dat );

        MAKE_LIST( sea::Object, men, norw, brit, germ, swe, dat );

        // Houses. Use aggregared object - color-house
        LOCAL_OBJECT( red_house );
        LOCAL_OBJECT( blue_house );
        LOCAL_OBJECT( green_house );
        LOCAL_OBJECT( yellow_house );
        LOCAL_OBJECT( white_house );

        MAKE_LIST( sea::Object, houses, red_house, blue_house, green_house, yellow_house, white_house );
       
        // One of them is the middle house
        MAKE_LIST( sea::Object, middle_house, red_house, blue_house, green_house, yellow_house, white_house );

        // One of them is the 1st house
        MAKE_LIST( sea::Object, first_house, red_house, blue_house, green_house, yellow_house, white_house );

        // One of them lives in blue house
        MAKE_LIST_BY( sea::Object, man_in_blue_house, blue_house, norw, brit, germ, swe, dat );

        // Pets
        LOCAL_OBJECT( dog );
        LOCAL_OBJECT( horse );
        LOCAL_OBJECT( cat );
        LOCAL_OBJECT( bird );
        LOCAL_OBJECT( fish );

        MAKE_LIST( sea::Object, pets, dog, horse, cat, bird, fish );

        // Drinks
        LOCAL_OBJECT( coffee );
        LOCAL_OBJECT( tea );
        LOCAL_OBJECT( water );
        LOCAL_OBJECT( milk );
        LOCAL_OBJECT( beer );

        MAKE_LIST( sea::Object, drinks, coffee, tea, water, milk, beer );
        
        // Smokes
        LOCAL_OBJECT( palmal );
        LOCAL_OBJECT( dunhil );
        LOCAL_OBJECT( blend );
        LOCAL_OBJECT( master );
        LOCAL_OBJECT( prince );

        MAKE_LIST( sea::Object, smokes, palmal, dunhil, blend, master, prince );

        LOCAL_OBJECT( right );
        LOCAL_OBJECT( left );
        MAKE_LIST2( sea::Object, a_neighbor, right, left );

        // One of them smokes blend
        MAKE_LIST_BY( sea::Object, man_smoking_blend, blend, norw, brit, germ, swe, dat );

        // One of them smokes dunhil
        MAKE_LIST_BY( sea::Object, man_smoking_dunhil, dunhil, norw, brit, germ, swe, dat );
        
        // Men by smokes
        MAKE_LIST_BY( sea::Object, men_smokes, smokes, norw, brit, germ, swe, dat );

        // All
        MAKE_LIST( sea::List, all, men, houses, pets, drinks, smokes );

        // Locations associations
        LOCAL_OBJECT( the_neighbor ); // Right or left is known

        // Facts

        /* 4 */  green_house->attach_left_of( white_house, the_neighbor );
        /* 14 */ norw.via( a_neighbor, man_in_blue_house );
        /* 9 */  norw += first_house;

        /* 5 */  green_house += coffee;
        /* 8 */  middle_house += milk; 


        /* 1 */  brit += red_house;
        /* 7 */  yellow_house += dunhil;

        /* 2 */  swe += dog;
        /* 3 */  dat += tea;

        /* 6 */  palmal += bird;

        /* 10 */ man_smoking_blend.via( a_neighbor, cat ); 
        /* 15 */ man_smoking_blend.via( a_neighbor, water );
        /* 11 */ man_smoking_dunhil.via( a_neighbor, horse );

        /* 12 */ master += beer;
        /* 13 */ germ += prince;
        
        //
        // * SOLVING THE PUZZLE *
        //

        // Options are listed in { o1, o2, ..., oN }
        // Variants are in [ v1, v2, ..., vN ] 

        // Which fact to take 1st?
        // Make 1st conclusion!

        // "Which is 1st house?" options: { r, g, b, w, y } => 
        //
        // { w } cannot be 1st, because it is on the right of { g }, so it could be only 2nd in theory => options: { r, g, b, y }
        // { b } cannot be 1st, because NORW lives in 1st house with neighbour in { b } house => options: { r, g, y }
        // { r } cannot be 1st house because BRIT lives in { r } house, and NORW lives in 1st house => options: { g, y }
        // { g } cannot be 1st house, because { w } is on its right, but 1st house neighbour is { b } = > options: { y } - fact

        // "Which house is 2nd?"
        // This is the fact: 2nd is { b } - fact

        // "Which house is 3rd?" or middle - this is something that has to have a solution too => what is middle? See below.

        // Based on prev conclusion placement variants are: [ y!, b!, r?, g?, w? ], or [ y!, b!, g?, w?, r? ] => options: { r, g }
        // { g } cannot be in the middle, because { g } drinks coffee and MIDDLE drinks MILK => middle options: { r } - fact

        // So basically after asking questions: what is the 1st, 2nd and 3d house - we have gotten final order=> stop iterations(!)
        // Final house order: [ y!, b!, r!, g!, w! ]

        // Define "middle": relationship path from that house to the first is the same as relationship path to the last => 
        // Find length of the path == 3d house in the list

        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // IMPORTANT!
        // It is not necessary to have correct order of the questions. Solving any ambiguity will take us to the solution.
        // So we could have chosen as 1st question: "which is the middle house?"
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        // "which is the middle(3rd) house?"
        // Arrange houses based on the known facts: { b } is 2nd, { g } is left of { w }
        // => [ ?, b!, ?, g?, w? ] or [ ?, b!, g?, w?, ? ], that leaves us middle house options: { y, r }

        // But lets start from the beginning...
        //
        // { b } cannot be MIDDLE, because { b } on the right of 1st, that is 2nd house => options: { r, g, w, y }
        // { g } cannot be MIDDLE, because { g } drinks coffee, but MIDDLE likes milk => options: { r, w, y } 
        // .... So after this conclusion placement variant [ ?, b, g, w, ? ] - is invalid, leaving us [ ?, b!, ?, g!, w! ],
        // .....that is { b } is 2nd, { g } is 4th, { w } is 5th
        // { w } cannot be MIDDLE, because { w } is on the right of { g }, making { g } 2nd, but 2nd is { b } => options: { r, y }
        // { y } cannot be MIDDLE, because if { y } is placed in the middle, { r } will end up to be the 1st house with BRIT, but NORW lives in 1st house = > options: { r } - fact
        
        // Final house order: [ y!, b!, r!, g!, w! ]

        // Lets take diff approach:
        // We have 5 houses { r, g, b, y, w } and each can be in positions { 1, 2, 3, 4, 5 }
        
        // { r } cannot be in 1st place, because BRIT lives in { r }, but NORW lives in 1st house
        // { r } cannot be in 2nd place, because { b } is 2nd
        // { r } current options: { 3, 4, 5 }

        // { g } cannot be in 1st place, because then { w } should be 2nd, but { b } is 2nd
        // { g } cannot be in 2nd place, because { b } is 2nd
        // { g } cannot be in 3d-middle place, because { g } likes coffee, but middle house likes milk
        // { g } options: { 4, 5 }
        // { g } cannot be in 5th place, because { w } is on the right of { g }, making { w } out of range
        // { g } is: { 4 } - result => remove it from { r } options:
        // { r } adjusted options are: { 3, 5 }

        // { b } is: { 2 } - fact/result

        // { y } can be 1st
        // { y } cannot be 2nd, because { b } is 2nd 
        // { y } can be 3d
        // { y } cannot be 4th, because { g } is 4th
        // { y } can be 5th = > current options: { 1, 3, 5 } 

        // { w } cannot be 1st, because it is on the right of { g }
        // { w } cannot be 2nd, { b } is 2nd
        // { w } cannot be 3rd, because that would make { g } 2nd, but 2nd is { b }
        // { w } cannot be 4th, because that would make { g } 3rd/middle, but { g } likes coffee, however middle likes milk
        // { w } is { 5 } - fact/result
        // { r } adjusted options: { 3 } - fact/result, 5 is removed
        // { y } adjusted options: { 1 } - fact/result, 5 & 3 are removed


        ////////////////

        // Build a variant
        // item -> { option1, option2,..., optionN } ===> item -> option_i
        // Check if it is true

        //
        // Task: Find exact placement of the houses: (why we choose this task? - actually it is irrelevant, we can take any uncertanty where { one } -> { many } )
        //
		// Create a list == a variant. Verify it against facts: { b } - is 2nd house, { g, w } - are placed one after another
        //
		//      Variant example: { r, g, b, y, w }, but we know that { g, w } are placed together(fact) &&
        //                                      { b } is 2nd => thus { g, w } cannot be @ 1st or 2nd position
		//      Variants after those conclusions are: { ?, b, g, w, ? } or { ?, b, ?, g, w }. Find representation of that.
        //      => { ? } is { y, r }  - subsets of variables placed in stead of { ? }


        // For each { r, g, b, y, w } i = 1, 2, 3, 4, 5
        //  check if belongs at i position verifying the facts related to placement => 1) b is 2nd 2) { g } is left of { w } 3) Middle drinks milk
        //  


        // Build a variant
        {
            LOCAL_OBJECT( unknown );
            LOCAL_LIST( variant );

            for( HIterator< > it( houses ); *it; it.advance( ) )
            {
                variant.as< sea::List >( )->attach_last( *it );
            }
        }

        ////////////////

        // Destroy
        brit->detach_all( );
        swe->detach_all( );
        dat->detach_all( );
        norw->detach_all( );

        green_house->detach_all( );

        palmal->detach_all( );
        dunhil->detach_all( );
        master->detach_all( );
        prince->detach_all( );

        milk->detach_all( );
        water->detach_all( );

        horse->detach_all( );
        cat->detach_all( );
    }
    SEA_MEM_LEAKS( );

#endif

#if 1
    {
        // Create apple and orange
        aref apple( NEW Object( "apple" ), false );
        aref orange( NEW Object( "orange" ), false );

        // Create properties/qualities/associations PQA
        aref color( "color" );
         aref red_color( "red.color" );
         aref orange_color( "orange.color" );

        color.has( red_color );
        color.has( orange_color );

        aref food( "food" );
         
        aref food_type( "food.type" );
          aref fruit( "fruit" );
          aref vegitable( "veitable" );

         aref taste( "taste" );
          aref sweet( "sweet" );
          aref bitter( "bitter" );

        food.has( food_type );
        food.has( taste );

        food_type.has( fruit );
        food_type.has( vegitable );

        taste.has( sweet );
        taste.has( bitter );

        aref shape( "shape" );
         aref shape_round( "shape.round" );
         aref shape_square( "shape.square" );

        shape.has( shape_round );
        shape.has( shape_square );

        aref smell( "smell" );
         aref smell_good( "smell.good" );
         aref smell_bad( "smell.bad" );

        smell.has( smell_good );
        smell.has( smell_bad );


        // Detroy
        color->detach_all( );
        taste->detach_all( );
        food->detach_all( );
        food_type->detach_all( );
        shape->detach_all( );
        smell->detach_all( );
	}
	SEA_MEM_LEAKS( );

#endif

#if 1
	// It's a boy!!!
    {
        int a = 9;
        int b = 1;

        // 1ST GRADE. 9 - 1 = ? or How 1 is related to 9
        // Simulating brain function....

        // Number of vocabulary items
        int total = 10;

        // Basic association - "link" between them
        aref via_next( "link" );

        // Create all vocabulary items
        aref d[ 10 ] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };

        // Create associations between them
        // 0 -> 1 -> 2...
        for ( int i = 0 ; i < total - 1; i++ )
        {
            d[ i ]->attach_left_of( d[ i + 1 ], via_next );
        }

        // Pick chosen items
        aref* obj_a = &d[ a ];
        aref* obj_b = &d[ b ];

        // Init enumerated association for building relationships/associations path
        Association via_next_a( 0, via_next.get( ) );

        // Create a relationships path - a "word"
        // typedef sea::ref< List > word;
        // sea::ref< List > word_of_relationships; 
        aref word_of_relationships;
        word_of_relationships << NEW List( via_next_a );

        // So far we dont know if the item B is on the right or on the left
        sea::Direction found_direction = sea::Direction::Neither;

        // Collect associations between A and B. 
        
        // Flip the coin and assume B is on the right.
        // Create "relationships path" - word == list of associations
        for( HIterator< > numbers_it( *obj_a, via_next ); *numbers_it; numbers_it.advance( ) )
        {
            if ( strcmp( numbers_it->as< char >( ), ( *obj_b )->as< char >( ) ) == 0 )
            {
                // Found the item, so stop collecting word of the associations
                found_direction = sea::Direction::Right;
                break;
            }

            // Add every association into the...
            word_of_relationships.as< sea::List >( )->attach_last( via_next );
        }

        // B on the right?
        if ( found_direction == sea::Direction::Neither )
        {
            // Nope...
            // Destroy previously collected relationships path
            word_of_relationships.as< sea::List >( )->clear( );

            // Collect associations between A and B. Assuming B is on the left.
            for( HIterator< sea::Object, sea::Left > i( *obj_a, via_next ); *i; i.advance( ) )
            {
                if ( strcmp( i->as< char >( ), ( *obj_b )->as< char >( ) ) == 0 )
                {
                    // Direction was chosen correctly - found the last object
                    found_direction = sea::Direction::Left;

                    break;
                }

                word_of_relationships.as< sea::List >( )->attach_last( via_next );
            }
        }

        ASSERT_DEBUG( found_direction != sea::Direction::Neither );

        // Found?
        if ( found_direction != sea::Direction::Neither )
        {
            // Yes,... prepare iteration through relationships and the vocabulary
            // Tricky point! Why we "gravitate" to start from the beginning of the vocabulary?
            //  => A: We always start comparing from the heads of both objects, that is the essence of comparing
            // Where did we get this knowledge?
            // Philosofical - we are programmed to start from the begining... measuring/comparing
            HIterator< > numbers_it( d[ 0 ], via_next );
            
            // Count using "fingers"
            for ( HIterator< sea::List > i( word_of_relationships ); *i && *numbers_it; i.advance( ), numbers_it.advance( ) );

            SEA_TRACE( "\nCounting... %d -> %d = %s%s ", 
                a, 
                b,
                found_direction == sea::Direction::Left ? "-" : "", numbers_it->as< char >( ) );
        }

        // Cleaup
        for ( int i = 0; i < total; i++ )
        {
            d[ i ]->detach_all( );
        }
    }
    SEA_MEM_LEAKS( );
#endif

    // Ded moroz lit up the stars. Stars are bright. Moon is also bright.
    // Did ded moroz lit up the moon?
#if 1
    {
        aref dedmoroz( "dedmoroz" );
        aref star( "star" );
        aref moon( "moon" );

        aref bright( "bright" );
        aref lightup( "lightup" );

        dedmoroz += lightup;
        lightup += star; 
        star += bright;
        moon += bright;

        // If star and moon are bright
        if ( star( bright ) && moon( bright ) )
        {
            // And star is litup by ded moroz
            if ( star( lightup ) && dedmoroz( lightup ) )
            {
                // And moon is not lit up...
                if ( !moon( lightup ) )
                {
                    // Fare to ask...
                    SEA_TRACE( "Did ded moroz lit up the moon?" );
                    moon += lightup;
                    if ( moon( lightup ) )
                    {
                        SEA_TRACE( "yes...?" );
                    }
                }
            }
        }

        for( VIterator< > i( bright ); *i; i++ )
        {
            SEA_TRACE( "%s is %s", i->as< char >( ), bright->as< char >( ) );
        }

        moon -= lightup;
        dedmoroz -= lightup;
        lightup -= star;

        moon -= bright;
        star -= bright;
    }
    SEA_MEM_LEAKS( );

#endif


    // Thread safe operations OBJECT
#if 0
    {
        SEA_TRACE( "\nThread safe list operations OBJECT" );
        SEA_TRACE("=====");
        
        int n = 100;
        {
            vector< thread1* > ar;
            sea::aref a; a << NEW Object;

            sea::aref the_obj = a;

            // Create and link objects
            for( int i = 0; i < n; i++ )
            {
                sea::aref b; b << NEW Object;
                b->attach_right_of( a, 1 );
                a = b;
            }

            // Create threads and pass one by one objects for distruction
            for( HIterator< > i( the_obj ); *i; i++ )
            {
                thread1* t = NEW thread1( *i );
                ar.insert( ar.end( ), t );
                t->start( );
            }

            for( unsigned i = 0; i < ar.size( ) ; i++ )
            {
                ar[ i ]->wait( );
                ar[ i ]->release_ref( );
            }
            ar.clear( );
        }

        SEA_MEM_LEAKS( );
    }
#endif

    // Thread safe list operations
#if 1
    {
        SEA_TRACE( "\nThread safe LIST operations" );
        SEA_TRACE("=====");
        {
            sea::ref< List > list; list << NEW List;

            vector< thread* > ar;
            int n = 50;
            for( int i = 0; i < n; i++ )
            {
                thread* a = NEW thread( list.get( ), i );
                ar.insert( ar.end( ), a );
                a->start( );
            }

            for( int i = 0; i < n; i++ )
            {
                ar[ i ]->wait( );
                ar[ i ]->release_ref( );
            }

            ar.clear( );
        }

        SEA_MEM_LEAKS( );
    }
#endif

    // detach from an object
#if 1
    {
        SEA_TRACE( "\ndetach from an object" );

        {
            aref a; a << NEW Object;
            aref color( "color" );
            aref smell( "smell" );
            aref red( "red" );

            color += red;
            for( VIterator< Object, Either > it( color ); *it; it++ )SEA_TRACE( "   %s", it->as< char >( ) );

            a += color;
            a += smell;

            for( VIterator< Object, Either > it( a ); *it; it++ )SEA_TRACE( "   %s", it->as< char >( ) );
            a -= color;

            for( VIterator< Object, Either > it( a ); *it; it++ )SEA_TRACE( "   %s", it->as< char >( ) );
            a -= smell;

            for( VIterator< Object, Either > it( a ); *it; it++ )SEA_TRACE( "   %s", it->as< char >( ) );
            color->detach_all( );
        }

        SEA_MEM_LEAKS( );
    }
#endif

    // ref contructors
#if 1
    {
        SEA_TRACE( "\nref contructors" );
        {
            aref a( get_x( ).get( ) );
        }
        SEA_MEM_LEAKS( );
        {
            aref a( NEW Object, false );
            aref b = a.get( );
            aref c( b ); 
            aref d = c;
        }

        SEA_MEM_LEAKS( );
    }
#endif

    // Insert LEFT
#if 1
    {
        {
            SEA_TRACE( "\nInsert LEFT" );
            SEA_TRACE("=====");

            aref a; a << NEW Object;
            aref b; b << NEW Object;
            aref c; c << NEW Object;
            aref d; d << NEW Object;
            aref f; f << NEW Object;

            a->insert_left_of( d, 1 );
            b->insert_left_of( d, 1 );
            c->insert_left_of( d, 1 );
            f->insert_left_of( a, 1 );

            b->detach( 1 );
            c->detach( 1 );
            a->detach( 1 );
            f->detach( 1 );
            d->detach( 1 );
        }

        SEA_MEM_LEAKS( );
    }
#endif

    // Insert RIGHT
#if 1
    {
        {
            SEA_TRACE( "\nInsert RIGHT" );
            SEA_TRACE("=====");

            aref a; a << NEW Object;
            aref b; b << NEW Object;
            aref c; c << NEW Object;
            aref d; d << NEW Object;

            a->insert_right_of( d, 1 );
            b->insert_right_of( d, 1 );
            c->insert_right_of( d, 1 );

            b->detach( 1 );
            c->detach( 1 );
            a->detach( 1 );
        }
        SEA_MEM_LEAKS( );
    }
#endif

    // Attach a -> b as 1 a -> c as 2
#if 1
    {
        {
            SEA_TRACE( "\nAttach a -> to many via diff associations" );
            SEA_TRACE("=====");

            aref a; a << NEW Object;
            aref b; b << NEW Object;
            aref c; c << NEW Object;
            aref d; d << NEW Object;

            a->attach_left_of( b, 1 );
            a->attach_left_of( c, 2 );
            a->attach_left_of( d, 3 );

            a->detach_all( );
        }

        SEA_MEM_LEAKS( );

        {
            aref a; a << NEW Object;
            vector< aref > ar;
            for( int i = 0; i < 1000; i++ )
            {
                aref x; x << NEW Object;
                ar.insert( ar.end( ), x );
                a->attach_left_of( x, i + 1 );
            }
            a->detach_all( );
        }

        SEA_MEM_LEAKS( );
    }
#endif

    // Attach LEFT
#if 1
    {
        {
            SEA_TRACE( "\nAttach LEFT" );
            SEA_TRACE("=====");

            aref a; a << NEW Object;
            aref b; b << NEW Object;
            aref c; c << NEW Object;
            aref d; d << NEW Object;

            a->attach_left_of( b, 1 );
            b->attach_left_of( c, 1 );
            c->attach_left_of( d, 1 );

            b->detach( 1 );
            c->detach( 1 );
            a->detach( 1 );
        }

        SEA_MEM_LEAKS( );
    }
#endif

    // Attach RIGHT
#if 1
    {
        {
            SEA_TRACE( "\nAttach RIGHT" );
            SEA_TRACE("=====");

            aref a; a << NEW Object;
            aref b; b << NEW Object;
            aref c; c << NEW Object;
            aref d; d << NEW Object;

            b->attach_right_of( a, 1 );
            c->attach_right_of( b, 1 );
            d->attach_right_of( c, 1 );

            b->detach( 1 );
            c->detach( 1 );
            a->detach( 1 );
        }

        SEA_MEM_LEAKS( );
    }
#endif

    // Poligamy assotiations:: B connects to A as '1', to C as '2' , to D as '1'
#if 1
    {
        {
            SEA_TRACE( "\nPoligamy assotiations:: B connects to A as '1', to C as '2' , to D as '1' " );
            SEA_TRACE("=====");

            aref a; a << NEW Object;
            aref b; b << NEW Object;
            aref c; c << NEW Object;
            aref d; d << NEW Object;

            a->attach_right_of( b, 1 );
            c->attach_right_of( b, 2 );
            d->attach_right_of( b, 1 );

            b->detach( 1 );
            b->detach( 2 );
        }

        SEA_MEM_LEAKS( );
    }
#endif

    // LIST attach Last/First
#if 1
    {
        {
            SEA_TRACE( "\nLIST attach Last/First" );
            SEA_TRACE("=====");

            sea::ref< List > list; list << NEW List;
            aref a; a << NEW Object;
            aref b; b << NEW Object;
            aref c; c << NEW Object;

            list->attach_first( a );
            list->attach_last( b );
            list->detach( c );

            list->detach( a );
            list->detach( b );
        }

        SEA_MEM_LEAKS( );
    }
#endif

    // LIST insert test
#if 1
    {
        {
            SEA_TRACE( "\nLIST insert test" );
            SEA_TRACE("=====");

            sea::ref< Queue > q; q << NEW Queue;

            aref a; a << NEW Object;
            aref c; c << NEW Object;
            aref d; d << NEW Object;
            aref x; x << NEW Object;

            q->push( a );
            q->push( c ); 
            q->push( d );

            // Right
            q->insert_right_of( a, x );
            q->detach( x );
            q->insert_right_of( c, x );
            q->detach( x );
            q->insert_right_of( d, x );
            q->detach( x );

            // Left
            q->insert_left_of( x, a );
            q->detach( x );
            q->insert_left_of( x, c );
            q->detach( x );
            q->insert_left_of( x, d );
            q->detach( x );

            SEA_TRACE(">> =====");
            for( HIterator<> it( q->get_first( ) ); *it; it++ )
            {
                SEA_TRACE("el %x rc %d link rc %d", *it, it->refs( ), it->get_link( ) != NULL ? it->get_link( )->refs( ) : 0 );
            }
            SEA_TRACE(">> =====");
        }

        SEA_MEM_LEAKS( );
    }
#endif

    // QUEUE test - CORRUPTS NEXT TEST!!!!
#if 1
    {
        {
            SEA_TRACE( "\nQUEUE test" );
            SEA_TRACE("=====");

            sea::ref< Queue > q; q << NEW Queue;
            int n = 10;

            for( int i = 0; i < n; i++ )
            {
                aref a; a << NEW Object;
                q->push( a );
            }

            SEA_TRACE(" =====");

            for( HIterator<> it( q->get_first( ) ); *it; it++ )
            {
                SEA_TRACE("el %x rc %d link rc %d", *it, it->refs( ), it->get_link( ) != NULL ? it->get_link( )->refs( ) : 0 );
            }

            aref a; a << NEW Object;
            q->insert_left_of( a, q->get_last( ) );

            SEA_TRACE(" =====");
            for( HIterator<> it( q->get_first( ) ); *it; it++ )
            {
                SEA_TRACE("el %x rc %d link rc %d", *it, it->refs( ), it->get_link( ) != NULL ? it->get_link( )->refs( ) : 0 );
            }

            for( int i = 0; i < n; i++ )
            {
                a = q->pop( ).get( );
            }
        }

        SEA_MEM_LEAKS( );
    }
#endif

    // ABBA test :: EnumObject association
#if 1
    {
        {
            SEA_TRACE( "\nABBA test :: EnumObject association" );
            SEA_TRACE("=====");

            sea::ref< List > abba; abba << NEW List( Association( 0, NULL ) );

            aref a( "a" );
            aref b( "b" );

            abba->attach_last( a );
            abba->attach_last( b );
            abba->attach_last( b );
            abba->attach_last( a );

            SEA_TRACE(" =====");
            String str;
            for( HIterator< > it( abba.get( ) ); *it; it++ )
            {
                SEA_TRACE("el %x rc %d link rc %d", *it, it->refs( ), it->get_link( ) != NULL ? it->get_link( )->refs( ) : 0 );
                str += it->as< char >( );
            }
            SEA_TRACE("%s", str.c_str( ) );
        }

        SEA_MEM_LEAKS( );
    }

#endif

    // TREE test 1
#if 1
    {
        {
            SEA_TRACE( "\nTREE test 1" );
            SEA_TRACE("=====");

            aref a( "a" );
            aref b( "b" );
            aref c( "c" );
            aref d( "d" );
            aref n( "n" );

            sea::ref< Tree > t; t << NEW Tree;
            
            t->attach( a, b, 1 );  //    A->B 1
            t->attach( b, c, 2 );  //       B->C 2
            t->attach( a, d, 3 );  //    A->D 3
            t->attach( n, a, 4 );  // N->A 4
            t->attach( b, c, 1 );  //       B->C 1

            t->detach_branch( b, 1 );
            t->detach_branch( b, 2 );
        }

        SEA_MEM_LEAKS( );
    }
#endif

    // TREE test 2
#if 1
    {
        {
            SEA_TRACE( "\nTREE test 2" );
            SEA_TRACE("=====");

            aref a( "a" );
            aref b( "b" );
            aref c( "c" );
            aref d( "d" );
            aref e( "e" );
            aref f( "f" );
            aref n( "n" );
            
            sea::ref< Tree > t; t << NEW Tree;

            t->attach( a, b, 1 );  // A->B 1
            t->attach( a, c, 2 );  // A->C 2
            t->attach( b, d, 1 );  //      B->D 1
            t->attach( b, e, 3 );  //      B->E 3
            t->attach( b, f, 4 );  //      B->F 4
            t->attach( a, n, 1 );  // N->A 1 - changing root
        }

        SEA_MEM_LEAKS( );
    }
#endif

    // LIST elements with CHAR data
#if 1
    {
        {
            SEA_TRACE( "\nLIST elements with CHAR data" );
            SEA_TRACE("=====");

            sea::ref< List > list; list << NEW List;;
            for( int i = 0; i < 26; i++ ) 
            {
                aref a( (unsigned int)( 'A' + i ) ); 
                list->attach_last( a );
            }

            SEA_TRACE( "list count:%d", list->size( ) );

            String str;
            for( HIterator< > it( list->get_first( ) ); *it; it++ ) 
            {
                char* ch = it->as< char >( );
                int int_ch[ 1 ];
                int_ch[ 0 ] = reinterpret_cast< int >( ch );
                str.insert( str.end( ), (char)int_ch[ 0 ] );
            }
            SEA_TRACE( "%s", str.c_str( ) );
        }

        SEA_MEM_LEAKS( );
    }
#endif

    // VERTICAL iterator on polygamy associations
#if 1
    {
        {
            SEA_TRACE( "\nVERTICAL iterator on polygamy associations" );
            SEA_TRACE("=====");

            aref a( "->A" );
            aref b( "->B" );
            aref c( "->C" );
            aref d( "->D" );
            aref e( "->E" );
            aref f( "->F" );
            aref g( "->G" );

            a->attach_right_of( b, 1 );
            c->attach_right_of( b, 1 );

            d->attach_right_of( b, 2 );
            e->attach_right_of( b, 2 );

            f->attach_right_of( b, 1 );
            g->attach_right_of( b, 2 );

            SEA_TRACE( "\n %s associated with the following by #1", b->as< char >( ) );
            for( VIterator< > i( b , 1 ); *i; i++ ) SEA_TRACE( "   %s", i->as< char >( ) );

            SEA_TRACE( "\n %s associated with the following by #2", b->as< char >( ) );
            for( VIterator< > i( b , 2 ); *i; i++ ) SEA_TRACE( "   %s", i->as< char >( ) );

            SEA_TRACE( "\n %s associated with the following by ANY", b->as< char >( ) );
            for( VIterator< > i( b ); *i; i++ ) SEA_TRACE( "   %s", i->as< char >( ) );

            b->detach_all( );
        }

        SEA_MEM_LEAKS( );
    }
#endif

    // Killing specific vertical association
#if 1
    {
        {
            SEA_TRACE( "\nKilling specific vertical association" );
            SEA_TRACE("=====");

            aref x( "->X" );
            aref a( "->A" );
            aref b( "->B" );
            aref c( "->C" );

            a->attach_right_of( x, 1 );  // X -> A by id = 1
            b->attach_right_of( x, 1 );  // X -> B by id = 1
            c->attach_right_of( x, 1 );  // X -> C by id = 1

            SEA_TRACE( "\n %s associated with the following by #1", x->as< char >( ) );
            for( VIterator< > i( x, 1 ); *i; i++ ) SEA_TRACE( "   %s", i->as< char >( ) );

            SEA_TRACE( "x->detach( 1 );" );
            x->detach( 1 );

            ASSERT_DEBUG( x->get_link( ) == NULL );
            ASSERT_DEBUG( x->refs( ) == 1 );

            SEA_TRACE( "\n %s associated with the following by #1", x->as< char >( ) );
            int j = 0;
            for( VIterator< > i( x, 1 ); *i; i++, j++ ) SEA_TRACE( "   %s", i->as< char >( ) );
            if ( j == 0 )
            {
                SEA_TRACE( "<EMPTY>");
            }
            else
            {
                ASSERT_DEBUG( j == 0 );
            }
        }

        SEA_MEM_LEAKS( );
    }

#endif

    // RANDOM Complex relationships
#if 1
    {
        {
            SEA_TRACE( "\nRANDOM Complex relationships" );
            SEA_TRACE("=====");

            const char* a1 = "husband";
            const char* a2 = "co-worker";
            const char* a3 = "human";

            aref x( "->X" );
            aref y( "->Y" );
                  
            aref a( "->A" );
            aref b( "->B" );
            aref c( "->C" );
            aref d( "->D" );
            
            // X -> A - 1st root in the tree. Connect to elements via 1
            x->attach_left_of( a, a1 );  // X -> A 1
            x->attach_left_of( c, a1 );  // X -> C 1

            // X -> A - 1st root in the tree. Connect to elements via 2
            x->attach_left_of( b, a2 );  // X -> B 2
            x->attach_left_of( d, a2 );  // X -> D 2

            // Y->... second root in the tree
            a->attach_right_of( y, a3 );  // Y -> A 3
            b->attach_right_of( y, a3 );  // Y -> B 3
            c->attach_right_of( y, a3 );  // Y -> C 3
            d->attach_right_of( y, a3 );  // Y -> D 3
            x->attach_right_of( y, a3 );  // Y -> X 3

            Link* l = x->get_link( a1 ).get( );
            SEA_TRACE( "\n %s related as '%s' with", x->as< char >( ), l->get_association( ).as< char >( ) );
            for( VIterator< > i( x, a1 ); *i; i++ ) SEA_TRACE( "   %s", i->as< char >( ) );

            l = x->get_link( a2 ).get( );
            SEA_TRACE( "\n %s related as '%s' with", x->as< char >( ), l->get_association( ).as< char >( ) );
            for( VIterator< > i( x, a2 ); *i; i++ ) SEA_TRACE( "   %s", i->as< char >( ) );

            l = y->get_link( a3 ).get( );
            SEA_TRACE( "\n %s related as '%s' with", y->as< char >( ), l->get_association( ).as< char >( ) );
            for( VIterator< > i( y, a3 ); *i; i++ ) SEA_TRACE( "   %s", i->as< char >( ) );

            SEA_TRACE(" Killing relationships one by one");
            {
                l = x->get_link( a1 ).get( );
                SEA_TRACE( "\n %s related as '%s' with", x->as< char >( ), l->get_association( ).as< char >( ) );
                for( VIterator< > i( x, a1 ); *i; i++ ) SEA_TRACE( "   %s", i->as< char >( ) );

                x->detach( a1 );
                ASSERT_DEBUG( x->get_link( a1 ) == NULL );
                SEA_TRACE(" No such relationship left");
            }

            {
                l = x->get_link( a2 ).get( );
                SEA_TRACE( "\n %s related as '%s' with", x->as< char >( ), l->get_association( ).as< char >( ) );
                for( VIterator< > i( x, a2 ); *i; i++ ) SEA_TRACE( "   %s", i->as< char >( ) );

                x->detach( a2 );
                ASSERT_DEBUG( x->get_link( a2 ) == NULL );
                SEA_TRACE(" No such relationship left");
            }

            {
                l = y->get_link( a3 ).get( );
                SEA_TRACE( "\n %s related as '%s' with", y->as< char >( ), l->get_association( ).as< char >( ) );
                for( VIterator< > i( y, a3 ); *i; i++ ) SEA_TRACE( "   %s", i->as< char >( ) );

                y->detach( a3 );
                ASSERT_DEBUG( y->get_link( a3 ) == NULL );
                SEA_TRACE(" No such relationship left");
            }

            /////////////////////////
            // Detaching all from A kills A as well.
            // y->detach_all( );
            // x->detach_all( );
        }

        SEA_MEM_LEAKS( );
    }
#endif

    // Tree relationships, killing some relationships and then all the rest
#if 1
    {
        {
            SEA_TRACE( "\nTree relationships, killing some relationships and then all the rest" );
            SEA_TRACE("=====");

            aref a; a << NEW Object;
            aref b; b << NEW Object;
            aref c; c << NEW Object;
            aref d; d << NEW Object;
            aref e; e << NEW Object;
            
            a->attach_left_of( b, 1 );
            c->attach_right_of( b, 2 );
            d->attach_right_of( b, 3 );
            e->attach_right_of( b, 4 );

            b->detach( 3 );
            b->detach( 2 );
            b->detach_all( );
        }

        SEA_MEM_LEAKS( );
    }
#endif

    // Associate Object derivatives
#if 1
    {
        {
            SEA_TRACE( "\nAssociate Object derivatives" );
            SEA_TRACE("=====");

            class Thing: public Object
            {
            public:
                Thing( ){ }
                ~Thing( ){ }
            };

            sea::ref< Thing > first; first << NEW Thing;

            for( int i = 0; i < 6; i++ )
            {
                sea::ref< Thing > aThing; aThing << NEW Thing;
                aThing->attach_right_of( reinterpret_cast< aref& >( first ), i + 1 );
            }
            first->detach_all( );
        }

        SEA_MEM_LEAKS( );
    }
#endif

    // Many associations between A and B
#if 1
    {
        {
            SEA_TRACE( "\nMany associations between A and B" );
            SEA_TRACE("=====");

            aref a; a << NEW Object;
            aref b; b << NEW Object;

            const char* q1 = "fruit";
            const char* q2 = "red";
            const char* q3 = "eatable";
            const char* q4 = "round";


            b->attach_right_of( a, q1 );
            b->attach_right_of( a, q2 );
            b->attach_right_of( a, q3 );
            b->attach_right_of( a, q4 );

            Link* l1 = a->get_link( q1 ).get( );
            Link* l2 = a->get_link( q2 ).get( );
            Link* l3 = a->get_link( q3 ).get( );
            Link* l4 = a->get_link( q4 ).get( );

            SEA_TRACE( "   %s", l1->get_association( ).as< char >( ) );
            SEA_TRACE( "   %s", l2->get_association( ).as< char >( ) );
            SEA_TRACE( "   %s", l3->get_association( ).as< char >( ) );
            SEA_TRACE( "   %s", l4->get_association( ).as< char >( ) );

            a->detach_all( );
        }

        SEA_MEM_LEAKS( );
    }
#endif

    // Stack
#if 1
    {
        {
            SEA_TRACE( "\nStack" );
            SEA_TRACE("=====");

            int n = 100;
            sea::ref< Stack > s; s << NEW Stack;
            vector< aref > v;

            for( int i = 0; i < n; i++ )
            {
                aref a; a << NEW Object;
                s->push( a );
                v.insert( v.end( ), a );
            }

            for( int i = 0; i < n; i++ )
            {
                sea::aref a = s->pop( );
                ASSERT_DEBUG( v[ n - i - 1 ] == a.get( ) );
            }
        }

        SEA_MEM_LEAKS( );
    }
#endif

    // Queue
#if 1
    {
        {
            SEA_TRACE( "\nQueue" );
            SEA_TRACE("=====");

            int n = 10;
            sea::ref< Queue > q; q << NEW Queue;
            vector< aref > v;

            for( int i = 0; i < n; i++ )
            {
                aref a; a << NEW Object;
                q->push( a );
                v.insert( v.end( ), a );
            }

            for( int i = 0; i < n; i++ )
            {
                sea::aref a = q->pop( );
                ASSERT_DEBUG( v[ i ] == a.get( ) );
            }
        }

        SEA_MEM_LEAKS( );
    }
#endif
}

// -------------------------------------------------------------------------------------------------

